/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language enrstuing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.enrstu.service.impl;

import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.enrstu.service.AdministrativeDivisionService;
import me.zhengjie.modules.enrstu.service.CommunityService;
import me.zhengjie.modules.enrstu.service.SchoolDistrictService;
import me.zhengjie.modules.enrstu.service.SchoolService;
import me.zhengjie.modules.enrstu.service.dto.*;
import me.zhengjie.modules.enrstu.service.mapstruct.SchoolDistrictMapper;

import me.zhengjie.modules.enrstu.domain.Community;
import me.zhengjie.modules.enrstu.domain.SchoolDistrict;
import me.zhengjie.modules.enrstu.repository.SchoolDistrictRepository;
import me.zhengjie.modules.enrstu.util.excel.EasyExcelUtil;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author yyx
* @date 2024-10-23
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class SchoolDistrictServiceImpl implements SchoolDistrictService {

    private final SchoolDistrictRepository districtRepository;
    private final CommunityService communityService;
    private final SchoolService schoolService;
    private final SchoolDistrictMapper districtMapper;
    private final AdministrativeDivisionService adService;
    private final UserRepository userRepository;



    @Override
    public PageResult<SchoolDistrictDto> queryAll(SchoolDistrictQueryCriteria criteria, Pageable pageable){
        if (ObjectUtil.isNotNull(criteria.getSchoolDistrictName())){
            if (criteria.getSchoolDistrictName().length() > 20){
                throw  new BadRequestException("学区名称不能超过20个字符");
            }
        }
        Page<SchoolDistrict> page = districtRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            Predicate predicate = QueryHelp.getPredicate(root, criteria, criteriaBuilder);
            criteriaQuery.orderBy(
                    criteriaBuilder.desc(root.get("gmtModified")));
            return predicate;
        },pageable);
        return PageUtil.toPage(page.getContent().stream()
                .map(schoolDistrict -> {

                    //通过公共服务的管理配置类获取学校、学区计算数量和查询列表的服务实现方法
                    SchoolDistrictDto schoolDistrictDto = districtMapper.toDto(schoolDistrict);

                    //根据学区id返回社区的数量和列表
                    schoolDistrictDto.setCommunityCount(communityService.total(schoolDistrict.getSchoolDistrictId()));
                    schoolDistrictDto.setSchoolCount(schoolService.total(schoolDistrict.getSchoolDistrictId()));

                    //根据学区id返回学校的数量和列表
                    schoolDistrictDto.setCommunityNameList(communityService.queryAll(schoolDistrict.getSchoolDistrictId()));
                    schoolDistrictDto.setSchoolNameList( schoolService.querySchoolList(schoolDistrict.getSchoolDistrictId()));
                    return schoolDistrictDto;
                })
                .collect(Collectors.toList()),page.getTotalElements());
    }

    @Override
    public List<SchoolDistrictDto> queryAll(SchoolDistrictQueryCriteria criteria){
        return districtMapper.toDto(districtRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public SchoolDistrictDto findById(String districtId) {
        SchoolDistrict district = districtRepository.findById(districtId).orElseGet(SchoolDistrict::new);
        ValidationUtil.isNull(district.getSchoolDistrictId(),"District","districtId",districtId);
        return districtMapper.toDto(district);
    }


    @Override
    @Transactional
    public void createOrUpdate(SchoolDistrictCreateAndUpdateDto resources, MultipartFile file) {
        if (ObjectUtil.isNotNull(resources.getSchoolDistrictName())){
            if (resources.getSchoolDistrictName().length() > 20 ){
                throw new BadRequestException("学区名称不能超过20个字符");
            }

        }
        if (ObjectUtil.isNull(resources.getSchoolDistrictId())){
            this.create(resources,file);
        }else{
            this.update(resources,file);
        }
    }
    @Transactional
    public void create(SchoolDistrictCreateAndUpdateDto resources, MultipartFile file) {
        log.info("resources：{}--:--file{}",resources,file);
        //判断学区名是否存在
        if(districtRepository.count((Root<SchoolDistrict> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
            return   cb.equal(root.get("schoolDistrictName"), resources.getSchoolDistrictName());}) > 0){
            throw new BadRequestException("学区名称已存在！");
        };
        if (ObjectUtil.isNull(resources.getSchoolDistrictName())){
            throw new BadRequestException("存在必填项未填写，请补充完整");
        }

        List<Community> communityList = new ArrayList<>();
        Community community = new Community();
        SchoolDistrict schoolDistrict = new SchoolDistrict();
        BeanUtils.copyProperties(resources,schoolDistrict);
        schoolDistrict.setSchoolDistrictId(IdUtil.simpleUUID());
        SchoolDistrict schoolDistrictSave = districtRepository.save(schoolDistrict);
        if (file != null){
            if (ObjectUtil.isNull(resources.getSheetName())){
                throw new BadRequestException("批量添加时需要指定上传文件具体sheet页！");
            }
            List<AdministrativeDivisionImportDto> returnDataList = upload(file, resources.getSheetName());
            communityService.createSaveBatch(returnDataList,schoolDistrictSave.getSchoolDistrictId());
        }else {

            AdministrativeDivisionTemplate administrativeDivision = new AdministrativeDivisionTemplate();
            BeanUtils.copyProperties(resources,administrativeDivision);

            //判断是否为直辖市
            boolean municipality = adService.isMunicipality(administrativeDivision.getProvince());
            String userName = userRepository.getById(SecurityUtils.getCurrentUserId()).getDept().getName();

            if (municipality){
                if(!administrativeDivision.getCounty().contains(userName)){
                    throw new BadRequestException("当前用户所在部门与导入数据中的区名称不匹配,请确认当前用户登录权限!");
                }
            }else{
                if(!administrativeDivision.getPrefecture().contains(userName)){
                    throw new BadRequestException("当前用户所在部门与导入数据中的市名称不匹配,请确认当前用户登录权限!");
                }
            }


            //开始添加社区
            community.setCommunityName(administrativeDivision.toString());
            community.setDistrictId(schoolDistrictSave.getSchoolDistrictId());
            community.setAdId(resources.getAdId ());

        }
        communityService.create(community,communityList);



    }

    @Transactional
    public void update(SchoolDistrictCreateAndUpdateDto resources, MultipartFile updateFile) {
        if (ObjectUtil.isNotNull(resources.getSchoolDistrictName())){
            if(ObjectUtil.isNull(resources.getSchoolDistrictId())){
                throw new BadRequestException("更新学区时，学区Id不能为空");
            }
            //根据学区id查询出学区，如果不存在，抛出异常
            SchoolDistrict district = districtRepository.findById(resources.getSchoolDistrictId()).orElseGet(SchoolDistrict::new);
            ValidationUtil.isNull( district.getSchoolDistrictId(),"District","id",resources.getSchoolDistrictId());
            //判断学区名是否存在
            if(districtRepository.count((Root<SchoolDistrict> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
                Predicate schoolDistrictName = cb.equal(root.get("schoolDistrictName"), resources.getSchoolDistrictName());
                Predicate id = cb.notEqual(root.get("schoolDistrictId"), resources.getSchoolDistrictId());
                return   cb.and(schoolDistrictName,id);}) > 0){
                throw new BadRequestException("学区名称已存在");
            };
            SchoolDistrict schoolDistrict = new SchoolDistrict();
            BeanUtils.copyProperties(resources,schoolDistrict);
            district.copy(schoolDistrict);
            //更新学区成功
            districtRepository.save(district);
            return;
        }
        //单个更新社区：
        if (ObjectUtil.isNotNull(resources.getProvince()) && ObjectUtil.isNotNull(resources.getProvince())
               && ObjectUtil.isNotNull(resources.getCounty()) && ObjectUtil.isNotNull(resources.getTown()) && ObjectUtil.isNotNull(resources.getVillage())){

           if(ObjectUtil.isNull(resources.getSchoolDistrictId())){
               throw new BadRequestException("更新社区时，学区Id不能为空");
           }
           if(ObjectUtil.isNull(resources.getCommunityId())){
               throw new BadRequestException("更新社区时，社区Id不能为空");
           }
           //判断社区名称是否一致
           AdministrativeDivisionTemplate administrativeDivision = new AdministrativeDivisionTemplate();
           BeanUtils.copyProperties(resources,administrativeDivision);

           if (communityService.isCommunityName(administrativeDivision.toString())){
               throw new BadRequestException("社区名称的新值与旧值一致，无需修改！！");
           }

           //开始更新
            communityService.updateSave(resources.getCommunityId(),administrativeDivision.toString());

       }
        if (ObjectUtil.isNotNull(updateFile)){
            if (ObjectUtil.isNull(resources.getSheetName())){
                throw new BadRequestException("批量修改社区时需要指定上传文件具体sheet页！");
            }
            List<AdministrativeDivisionImportDto> updateDateUploadList = upload(updateFile, resources.getSheetName());

            communityService.createSaveBatch(updateDateUploadList,resources.getSchoolDistrictId());
        }
    }




    @Transactional
    @Override
    public void delete(String id,Boolean isDeleteSdId) {
        //是否删除社区信息
        if (isDeleteSdId){
            communityService.delete(id);
        }else {
            if (ObjectUtil.isNull(id)){
                throw new BadRequestException("学区id不能为空！");
            }
            SchoolDistrictDto byId = this.findById(id);
            if (communityService.total(id) > 0 || schoolService.total(id) > 0){
                throw new BadRequestException("该学区下有社区或学校，无法删除！");
            }
            districtRepository.deleteById(byId.getSchoolDistrictId());
        }

    }

    @Override
    public void download(List<SchoolDistrictDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (SchoolDistrictDto district : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("学区名称", district.getSchoolDistrictName());
            map.put("学校数量", communityService.total(district.getSchoolDistrictId()));
            map.put("学区数量", schoolService.total(district.getSchoolDistrictId()));
            map.put("创建时间戳", district.getGmtCreate());
            map.put("更新时间戳", district.getGmtModified());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void download(HttpServletResponse response) throws IOException {
        Map<String,Object> map = new LinkedHashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        map.put("省", "");
        map.put("市", "");
        map.put("区、县", "");
        map.put("街道", "");
        map.put("社区 ", "");
        list.add(map);
        FileUtil.downloadExcel(list, response);

    }

    /**
     * 导入表格，获取表格数据
     * @param file /
     * @param sheetName /
     * @return /
     */
    @Override
    public  List<AdministrativeDivisionImportDto> upload(MultipartFile file, String sheetName) {
        return EasyExcelUtil.batchImport(AdministrativeDivisionImportDto.class, file, sheetName);
    }

    /**
     * 公共方法：查询学区信息
     * @return
     */
    @Override
    public List<SchoolDistrictCommonServiceDto> querySchoolDistrict()  {
         return districtRepository.findAll().stream().map(schoolDistrict -> {
            SchoolDistrictCommonServiceDto schoolDistrictCommonServiceDto = new SchoolDistrictCommonServiceDto();
            BeanUtils.copyProperties(schoolDistrict,schoolDistrictCommonServiceDto);
            //根据学区id返回社区的数量和列表
            schoolDistrictCommonServiceDto.setCommunityCount(communityService.total(schoolDistrict.getSchoolDistrictId()));
            schoolDistrictCommonServiceDto.setSchoolCount(schoolService.total(schoolDistrict.getSchoolDistrictId()));
            return schoolDistrictCommonServiceDto;
        }).collect(Collectors.toList());

    }
}